package com.nmgolden.lanxin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nmgolden.lanxin.api.AddressBookApi;
import com.nmgolden.lanxin.api.AuthApi;
import com.nmgolden.lanxin.api.MediaApi;
import com.nmgolden.lanxin.api.NotificationApi;
import com.nmgolden.lanxin.exception.LanxinException;
import com.nmgolden.lanxin.model.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.Header;

import java.io.File;
import java.time.Instant;
import java.util.*;

/**
 * @author siger
 * @date 2020/12/20 10:29 上午 Wechat:Z2013111158
 */

@SuppressWarnings("unused")
@Slf4j
public class DefaultLanxinService implements LanxinService {

    private final LanxinAppConfig mConfig;
    private final LanxinTokenManager mLanxinTokenManager;
    private final NotificationApi mLanxinNotificationApi;
    private final AuthApi mAuthApi;
    private final AddressBookApi mAddressBookApi;
    private final MediaApi mMediaApi;

    @SneakyThrows
    public DefaultLanxinService(LanxinAppConfig config) {

        LanxinAppConfig.verify(config);
        LanxinHttpClient mLanxinHttpClient = new LanxinHttpClient(config.getMaxConnections(), config.getMaxConnectionsPerRoute());

        mConfig = config;
        mLanxinTokenManager = new LanxinTokenManager(config, mLanxinHttpClient);
        mLanxinNotificationApi = new NotificationApi(config, mLanxinHttpClient, mLanxinTokenManager);
        mAuthApi = new AuthApi(config, mLanxinHttpClient, mLanxinTokenManager);
        mAddressBookApi = new AddressBookApi(config, mLanxinHttpClient, mLanxinTokenManager);
        mMediaApi = new MediaApi(config, mLanxinHttpClient, mLanxinTokenManager);
    }

    @Override
    public SignaturePackage getSignaturePackage(String url) {
        String nonceStr = getNonceStr();
        Instant timestamp = Instant.now();

        String rawSignatureStr = String.format("js_api_token=%s&noncestr=%s&timestamp=%s&url=%s",
                mLanxinTokenManager.getJsApiToken(), nonceStr, timestamp.getEpochSecond(), url);
        String signature = DigestUtils.sha1Hex(rawSignatureStr);

        SignaturePackage sp = new SignaturePackage();
        sp.setAppId(mConfig.getAppId());
        sp.setNonceStr(nonceStr);
        sp.setTimestamp(timestamp.getEpochSecond());
        sp.setSignature(signature);
        sp.setUrl(url);
        return sp;
    }

    @Override
    public String createUser(CreateUserRequestBody requestBody) {
        return mAddressBookApi.createUser(requestBody);
    }

    @Override
    public List<CreateUsersResponseItem> createUsers(List<CreateUserRequestBody> users) {
        JSONArray items = mAddressBookApi.createUsers(users);
        List<CreateUsersResponseItem> result = new ArrayList<>();
        for (int i = -1; ++i < items.size(); ) {
            JSONObject jsonObject = items.getJSONObject(i);
            CreateUsersResponseItem ci = new CreateUsersResponseItem();
            ci.setErrCode(jsonObject.getInteger("errCode"));
            // 此处字段名和对象属性名不匹配，所以你遍历
            ci.setStaffId(jsonObject.getString("staffid"));
            ci.setErrMsg(jsonObject.getString("errCode"));
            result.add(ci);
        }

        return result;
    }

    /**
     * 获取根分支的id（appId前半段+"-0",如appId为8798976-16252928，则根分支id为8798976-0）
     */
    @Override
    public String getRootDepartmentId() {
        return mConfig.getAppId().split("-")[0] + "-0";
    }

    @Override
    public String getOrgId() {
        return mConfig.getOrgId();
    }

    @Override
    public String createDepartment(CreateDepartmentRequestBody requestBody) {
        return mAddressBookApi.createDepartment(requestBody);
    }

    @Override
    public void updateDepartment(String deptId, UpdateDepartmentRequestBody requestBody) {
        mAddressBookApi.updateDepartment(deptId, requestBody);
    }

    @Override
    public void deleteDepartment(String deptId) {
        mAddressBookApi.deleteDepartment(deptId);
    }

    @Override
    public Department getDepartment(String departmentId) {
        return mAddressBookApi.getDepartment(departmentId);
    }

    @Override
    public List<Department> getDepartments(String departmentIds) {
        if (null == departmentIds || departmentIds.isEmpty()) {
            throw new LanxinException("departmentIds 不可为空！");
        }
        String[] idArr = departmentIds.split(",");
        List<Department> departmentList = new ArrayList<>();
        for (int i = -1; ++i < idArr.length; ) {
            departmentList.add(getDepartment(idArr[i]));
        }
        return departmentList;
    }

    /**
     * 获取子部门
     *
     * @param departmentId 父分支ID，根分支使用 “xxxx-0”，例如：524288-0
     */
    @Override
    public List<Department> getSubDepartments(String departmentId) {
        return mAddressBookApi.getSubDepartments(departmentId);
    }


    private List<Department> getDepartmentDeeply(Department dept, String deptId) {
        return null;
    }

    @Override
    public List<Department> getAllSubDepartments(String departmentId) {
        return getAllSubDepartments(departmentId, null);
    }

    @Override
    public List<User> getUsersInDepartment(String departmentId) {

        int curPage = 0;
        Boolean hasMore;
        List<User> userList = new ArrayList<>();
        do {
            curPage++;
            JSONObject data = mAddressBookApi.getUsersInDepartment(curPage, 100, departmentId);
            JSONArray staffs = data.getJSONArray("staffs");
            if (staffs != null) {
                for (int i = -1; ++i < staffs.size(); ) {
                    JSONObject jo = staffs.getJSONObject(i);
                    User user = jo.toJavaObject(User.class);
                    userList.add(user);
                }
            }

            hasMore = data.getBoolean("hasMore");
        }
        while (hasMore);

        return userList;
    }

    @Override
    public List<User> getAllUsersInDepartment(String departmentId) {
        List<User> userList = getUsersInDepartment(departmentId);

        List<Department> departmentList = getAllSubDepartments(departmentId, null);
        for (Department d : departmentList) {
            List<User> curUserList = getUsersInDepartment(d.getId());
            userList.addAll(curUserList);
        }
        return userList;
    }

    @Override
    public void addMember2Department(String deptId, String staffId) {
        mAddressBookApi.addMember(deptId, staffId);
    }

    @Override
    public void removeMemberFromDepartment(String deptId, String staffId) {
        mAddressBookApi.removeMember(deptId, staffId);
    }

    @Override
    public void moveDepartment(String deptId, String newParentId) {
        mAddressBookApi.moveDepartment(deptId, newParentId);
    }

    /**
     * 递归获取所有子部门
     */
    private List<Department> getAllSubDepartments(String departmentId, List<Department> departmentList) {
        if (departmentList == null) {
            departmentList = new ArrayList<>();
        }
        List<Department> curList = mAddressBookApi.getSubDepartments(departmentId);
        if (curList != null) {
            departmentList.addAll(curList);
            for (Department subDepartment : curList) {

                if (subDepartment.getHasChildren()) {
                    getAllSubDepartments(subDepartment.getId(), departmentList);
                }
            }
        }

        return departmentList;
    }

    @Override
    public MsgResponseData sendAppCardMessage(List<String> userIds, AppCardMsgDataInfo appCardMsgDataInfo) {
        AppCardMsgData appCardMsgData = new AppCardMsgData();
        appCardMsgData.setAppCard(appCardMsgDataInfo);
        return mLanxinNotificationApi.sendMessage(userIds, null, appCardMsgData);
    }

    @Override
    public void updateDynamicAppCardMsg(String msgId, AppCardUpdateMsgDataInfo msgDataInfo) {
        AppCardUpdateMsgData msgData = new AppCardUpdateMsgData();
        msgData.setAppCardUpdateMsg(msgDataInfo);
        mLanxinNotificationApi.updateDynamicCardMsg(msgId, msgData);
    }

    @Override
    public MsgResponseData sendOaCardMessage(String userIds, String title, String subtitle, List<MsgDataField> fields, String linkUrl) {
        List<String> userIdList = Optional.ofNullable(userIds).map(ids -> Arrays.asList(ids.split(","))).orElse(null);
        OACardMsgDataInfo info = new OACardMsgDataInfo();
        info.setTitle(title);
        info.setSubtitle(subtitle);
        info.setLink(linkUrl);
        info.setFields(fields);

        return mLanxinNotificationApi.sendMessage(userIdList, null, new OACardMsgData(info));
    }

    @Override
    public MsgResponseData sendTextMessage(String userIds, String text) {
        List<String> userIdList = Optional.ofNullable(userIds).map(strs -> strs.split(",")).map(Arrays::asList).orElse(null);
        return sendTextMessage(userIdList, text);
    }

    @Override
    public MsgResponseData sendTextMessage(List<String> userIds, String text) {

        if (null == text || text.isEmpty()) {
            throw new IllegalArgumentException("text 不可为空！");
        }

        TextMsgData data = new TextMsgData();
        TextMsgDataInfo info = new TextMsgDataInfo();
        info.setContent(text);
        data.setText(info);

        return mLanxinNotificationApi.sendMessage(userIds, null, data);
    }

    @Override
    public MsgResponseData sendLinkCardMessage(String userIds, String departmentIds,
                                               String title, String description,
                                               String iconLink, String link, String fromName, String fromIconLink) {

        List<String> userIdList = Optional.ofNullable(userIds).map(ids -> Arrays.asList(ids.split(","))).orElse(null);
        List<String> departmentIdList = Optional.ofNullable(departmentIds).map(ids -> Arrays.asList(ids.split(","))).orElse(null);

        return sendLinkCardMessage(userIdList, departmentIdList, title, description, iconLink, link, fromName, fromIconLink);
    }

    @Override
    public MsgResponseData sendLinkCardMessage(List<String> userIds, List<String> departmentIds, String title, String description, String iconLink, String link, String fromName, String fromIconLink) {

        return sendLinkCardMessage(userIds, departmentIds, title, description, iconLink, link, null, fromName, fromIconLink);
    }

    /**
     * 发送 linkCard 类型的通知消息
     *
     * @param userIds       多个用户（人员） id
     * @param departmentIds 多个部门（分支） id
     * @param title         标题
     * @param description   描述
     * @param iconLink      图标
     * @param link          连接
     * @param pcLink        pc 端链接
     * @param fromName      来源
     * @param fromIconLink  来源连接
     */
    @Override
    public MsgResponseData sendLinkCardMessage(List<String> userIds, List<String> departmentIds, String title, String description, String iconLink, String link, String pcLink, String fromName, String fromIconLink) {
        LinkCardMsgData data = new LinkCardMsgData();
        LinkCardMsgDataInfo info = new LinkCardMsgDataInfo();
        info.setTitle(title);
        info.setDescription(description);
        info.setIconLink(iconLink);
        info.setLink(link);
        info.setPcLink(pcLink);
        info.setFromName(fromName);
        info.setFromIconLink(fromIconLink);
        data.setLinkCard(info);

        return mLanxinNotificationApi.sendMessage(userIds, departmentIds, data);
    }

    @Override
    public void sendNotification(String senderId, List<String> receiverIds, String outline, String msgType, MsgData data) {
        mLanxinNotificationApi.sendNotification(senderId, receiverIds, outline, msgType, data);
    }

    @Override
    public void updateNotificationStatus(String userId, Integer unreadCount) {
        mLanxinNotificationApi.updateNotificationStatus(userId, unreadCount, null, new Date().getTime());
    }

    @Override
    public void updateNotificationStatus(String userId, Boolean noDisturb) {
        mLanxinNotificationApi.updateNotificationStatus(userId, null, noDisturb, new Date().getTime());
    }

    @Override
    public JSONObject getNotificationStatus(String userId) {
        return mLanxinNotificationApi.getNotificationStatus(userId);
    }

    @Override
    public void revokeMessage(String chatType, String senderId, String messageIds, String content, String mediaId) {
        mLanxinNotificationApi.revokeMessage(chatType, senderId, Arrays.asList(messageIds.split(",")), content, mediaId);
    }

    @Override
    public SendEventNotificationSubStatusItem sendAppChangeEvent(String userId, Boolean hasNew, Integer unreadNum) {
        return sendAppChangeEvent(userId, hasNew, unreadNum,null);
    }

    @Override
    public SendEventNotificationSubStatusItem sendAppChangeEvent(String userId, Boolean hasNew, Integer unreadNum, String entryId) {

        Map<String, Object> eventData = new HashMap<>();
        eventData.put("hasNew", hasNew);
        eventData.put("unread", unreadNum);
        AppEventNotification event = new AppEventNotification();
        event.setReceiverIds(Collections.singletonList(userId));
        event.setEventType("app_changes");
        event.setEventData(JSON.toJSONString(eventData));
        event.setVersion(getMicroTimestamp());
        event.setExpires(0);
        event.setChannelType(2);
        event.setEntryId(entryId);
        List<AppEventNotification> events = new ArrayList<AppEventNotification>() {{
            add(event);
        }};
        return mLanxinNotificationApi.sendEventNotifications(events).get(0);
    }


    /**
     * 每次请求自动更新本地user access token
     */
    @Override
    public String login(String code) {
        UserAccessToken token = mLanxinTokenManager.getUserToken(code);
        return token.getStaffId();
    }

    @Override
    public String getStaffIdByCode(String code) {
        UserAccessToken token = mLanxinTokenManager.getUserToken(code);
        return token.getStaffId();
    }

    @Override
    public String getStaffIdByQrcode(String qrcode) {
        return mAuthApi.getStaffIdByQrcode(qrcode);
    }

    @Override
    public List<User> getUsersByTagName(String tagName) {
        List<String> idList = findTagIds(new ArrayList<String>() {{
            add(tagName);
        }});
        if (idList.isEmpty()) {
            throw new LanxinException("未找到标签\"" + tagName + "\"!");
        }
        List<String> userIds = getUserIdsInTags(idList);
        return getUsers(userIds);
    }


    private List<String> getUserIdsInTags(List<String> tags) {
        List<String> userIds = new ArrayList<>();
        for (String tagId : tags) {
            userIds.addAll(mAddressBookApi.getUserIdsInTag(tagId));
        }

        return userIds;
    }

    @Override
    public List<List<Department>> getDepartmentAncestors4User(String staffId) {
        return mAddressBookApi.getDepartmentAncestors4User(staffId);
    }

    @Override
    public User getUser(String staffId) {
        return mAddressBookApi.getUser(staffId);
    }

    @Override
    public UserDetail getUserDetail(String staffId) {
        return mAddressBookApi.getUserDetail(staffId);
    }

    @Override
    public String getStaffId(String idType, String idValue) {
        return mAddressBookApi.getStaffId(idType, idValue);
    }

    @Override
    public void updateUser(String staffId, Map<String, Object> data) {
        // 将Map转换为JSON字符串
        String jsonString = JSON.toJSONString(data);
        JSONObject jsonObject = JSON.parseObject(jsonString);

        // 将JSONObject转换为对象
        UpdateUserRequestBody requestBody = jsonObject.toJavaObject(UpdateUserRequestBody.class);
        requestBody.setStaffId(staffId);
        updateUser(requestBody);
    }

    @Override
    public void updateUser(UpdateUserRequestBody requestBody) {
        mAddressBookApi.updateUser(requestBody.getStaffId(), requestBody);
    }

    @Override
    public List<LanxinResponse> updateUsers(List<UpdateUserRequestBody> requestBody) {
        JSONArray objects = mAddressBookApi.updateUsers(requestBody);
        return objects.toJavaList(LanxinResponse.class);
    }

    @Override
    public void deleteUser(String staffId) {
        mAddressBookApi.deleteUser(staffId);
    }

    @Override
    public SearchResult searchUser(Integer pageNum, Integer pageSize, String staffId, String keyword, Boolean recursive, List<String> sectorIds) {
        SearchRequestBody rb = new SearchRequestBody();
        rb.setKeyword(keyword);
        rb.setRecursive(recursive);
        rb.setSearchScope(new SearchRequestBody.SearchScope(sectorIds));
        return mAddressBookApi.searchUser(pageNum, pageSize, staffId, rb);
    }


    @Override
    public List<User> getUsers(String userIds) {
        List<String> userIdList = Arrays.asList(userIds.split(","));
        return getUsers(userIdList);
    }

    public List<User> getUsers(List<String> userIds) {
        List<User> users = new ArrayList<>();
        for (String userId : userIds) {
            users.add(getUser(userId));
        }
        return users;
    }

    @Override
    public String getCompleteAuthUrl(String state, String redirectUrl) {
        String AUTH_URL_TEMPLATE = "%s/oauth2/authorize?appid=%s&response_type=code&scope=SCOPE&state=%s&redirect_uri=%s";
        return String.format(AUTH_URL_TEMPLATE, mConfig.getAuthUrl(), mConfig.getAppId(), state, redirectUrl);
    }

    @Override
    public List<User> getOperators() {
        JSONObject data = mAuthApi.getOperators();
        return JSON.parseArray(data.getString("staffs"), User.class);
    }

    @Override
    public List<ExtraField> getExtraFields() {
        return mAddressBookApi.getExtraFields();
    }


    @Override
    public BotMsgResponseData sendMsgByBot(String url, MsgData msgData) {

        return sendMsgByBot(url, msgData.getMsgDataInfo());
    }

    @Override
    public BotMsgResponseData sendMsgByBot(String url, MsgDataInfo msgDataInfo) {

        return sendMsgByBot(url, null, msgDataInfo);
    }

    @Override
    public BotMsgResponseData sendMsgByBot(String url, String secret, MsgDataInfo msgDataInfo) {

        return mLanxinNotificationApi.sendMsgByBot(url, secret, msgDataInfo);
    }

    /**
     * 通过标签名称获得标签id
     */
    private List<String> findTagIds(List<String> tagNameList) {
        List<String> tagIds = new ArrayList<>();
        List<TagGroup> groups = mAddressBookApi.getTagGroups();
        for (TagGroup group : groups) {
            for (Tag tag : group.getTags()) {
                for (String leaderTagName : tagNameList) {
                    if (tag.getTagName().endsWith(leaderTagName)) {
                        tagIds.add(tag.getTagId());
                    }
                }
            }
        }
        return tagIds;
    }

    /**
     * 获取分支领导对应的标签名称
     */
    private List<String> makeLeaderTagNames(List<String> branchNames) {
        List<String> leaderTagNames = new ArrayList<>();
        for (String branchName : branchNames) {
            String tagSuffix = "";
            if (!branchName.endsWith("领导")) {
                tagSuffix = "领导";
            }
            leaderTagNames.add(branchName + tagSuffix);
        }
        return leaderTagNames;
    }


    private String getNonceStr() {
        return UUID.randomUUID().toString();
    }


    @Override
    public Map<String, String> uploadMedia(File file, String type) {

        JSON json = mMediaApi.uploadMedia(file, type);

        return (Map<String, String>) json;
    }

    @Override
    public void downloadMedia(String mediaId, String location) {

        mMediaApi.downloadMedia(mediaId, location);

    }

    @Override
    public Media getMedia(String mediaId) {
        return mMediaApi.getMedia(mediaId);
    }

    @Override
    public void downloadFileByShareId(String shareId, String path) {
        mMediaApi.downloadByShareId(shareId, path);
    }

    @Override
    public List<Header> getHeadersByShareId(String shareId) {
        return mMediaApi.getHeadersByShareId(shareId);
    }

    @Override
    public LanxinAppConfig getConfig() {

        return mConfig;
    }

    private Long getMicroTimestamp() {
        Instant now = Instant.now();
        return now.getEpochSecond() * 1_000_000 + now.getNano() / 1_000;
    }


}
